package nl.cypherpunk.statefuzzer;

import de.learnlib.api.logging.LearnLogger;
import net.automatalib.words.Alphabet;
import nl.cypherpunk.statefuzzer.fuzzing.FuzzingBasedState;
import nl.cypherpunk.statefuzzer.fuzzing.FuzzingBlackbox;
import nl.cypherpunk.statefuzzer.fuzzing.SUT;
import nl.cypherpunk.statefuzzer.openvpn.VPNConfig;
import nl.cypherpunk.statefuzzer.openvpn.VPNSUL;
import nl.cypherpunk.statefuzzer.rtsp.RTSPConfig;
import nl.cypherpunk.statefuzzer.rtsp.RTSPSUL;
import nl.cypherpunk.statefuzzer.smtp.SMTPConfig;
import nl.cypherpunk.statefuzzer.smtp.SMTPSUL;
import nl.cypherpunk.statefuzzer.tls.TLSConfig;
import nl.cypherpunk.statefuzzer.tls.TLSSUL;

import java.io.File;
import java.io.IOException;
import java.util.Date;

public class Fuzzing {
    LearningConfig config;
    Alphabet<String> alphabet;
    Alphabet<String> meaning;
    SUT<String, String> sul;
    public int learnTime;
    public Fuzzing(LearningConfig config) throws Exception {
        this.config = config;
        File outputDir = new File(config.output_dir);
        outputDir.mkdirs();
        LearnLogger log = LearnLogger.getLogger(Learner.class.getSimpleName());

        // Check the type of learning we want to do and create corresponding configuration and SUL
        if(config.type == LearningConfig.TYPE_TLS) {
            log.logConfig("Using TLS SUL");

            // Create the TLS SUT
            sul = new TLSSUL(new TLSConfig(config));
            alphabet = ((TLSSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_VPN){
            sul = new VPNSUL(new VPNConfig(config));
            alphabet = ((VPNSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_SMTP){
            sul = new SMTPSUL(new SMTPConfig(config));
            alphabet = ((SMTPSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_RTSP){
            sul = new RTSPSUL(new RTSPConfig(config));
            alphabet = ((RTSPSUL)sul).getAlphabet();
        }
    }

    public Fuzzing(Learner learner) throws Exception {
        this.config = learner.config;
        if(config.type == LearningConfig.TYPE_TLS) {
            sul = (TLSSUL) learner.sul;
            alphabet = ((TLSSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_VPN){
            sul = (VPNSUL) learner.sul;
            alphabet = ((VPNSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_SMTP){
            sul = (SMTPSUL) learner.sul;
            alphabet = ((SMTPSUL)sul).getAlphabet();
        }
        else if(config.type == LearningConfig.TYPE_RTSP){
            sul = (RTSPSUL) learner.sul;
            alphabet = ((RTSPSUL)sul).getAlphabet();
        }

        //File outputDir = new File(config.output_dir);
        //outputDir.mkdirs();
        LearnLogger log = LearnLogger.getLogger(Learner.class.getSimpleName());
    }

    public void fuzz(int fuzzTime) throws Exception, IOException, InterruptedException {

        System.out.println("Using TLS SUL");
        //FuzzingBlackbox fuzzingBlackbox = new FuzzingBlackbox(this.config,this.config.output_dir+File.separator+"learnedModel.dot", sul, alphabet);
        FuzzingBlackbox fuzzingBlackbox = new FuzzingBlackbox(this.config,"learnedModel.dot", sul, alphabet);

        // define the fuzzing number on every state
        fuzzingBlackbox.randomWalkWithFuzzing(50, fuzzTime- this.learnTime);
    }

    public void fuzzAfterLearn(int fuzzTime) throws Exception, IOException, InterruptedException {
        //System.out.println("Using TLS SUL");
        FuzzingBlackbox fuzzingBlackbox = new FuzzingBlackbox(this.config,this.config.output_dir+File.separator+"learnedModel.dot", sul, alphabet);
        //FuzzingBasedTesting fuzzingBasedTesting = new FuzzingBasedTesting(this.config,"learnedModel.dot", sul, alphabet);
        // define the fuzzing number on every state
        fuzzingBlackbox.randomWalkWithFuzzing(50, fuzzTime - this.learnTime);
    }

    public void fuzzBasedState(int fuzzTime) throws Exception, IOException, InterruptedException {
        //System.out.println("Using TLS SUL");
        FuzzingBasedState fuzzBasedState = new FuzzingBasedState(this.config,this.config.output_dir+File.separator+"learnedModel.dot", sul, alphabet);
        //FuzzingBasedState fuzzBasedState = new FuzzingBasedState(this.config,"learnedModel.dot", sul, alphabet);
        // define the fuzzing number on every state
        fuzzBasedState.randomWalkWithFuzzing(50, fuzzTime - this.learnTime);
    }

    public static void main(String[] args) throws Exception {
        if(args.length < 1) {
            System.err.println("Invalid number of parameters");
            System.exit(-1);
        }
        Date startDate = new Date();
        int starttime = (int)startDate.getTime()/1000;
        LearningConfig config = new LearningConfig(args[0]);

        int totalTime = Integer.parseInt(args[1]);
        Learner learner = new Learner(config);
        learner.learn();
        Date middelDate = new Date();
        int middletime = (int)middelDate.getTime()/1000;

        Fuzzing fuzz = new Fuzzing(config);
        fuzz.learnTime = middletime - starttime;

        fuzz.fuzzBasedState(totalTime);

        /*Fuzzing fuzz = new Fuzzing(config);
        fuzz.fuzz(totalTime);*/


        Date endDate = new Date();
        int minutes = (int) ((endDate.getTime() - startDate.getTime())/(1000 * 60));

        System.out.println("The learn time is "+ fuzz.learnTime +" minutes");
        System.out.println("The total time is "+ minutes +" minutes");
    }
}
